<template>
  <div class="customize-container" :style="{
    height: height
  }"
  >
    <div class="customize-table-container" style="height: calc(100% - 50px);">
      <table ref="customizeTable" class="customize-table" :width="width">
        <thead>
        <th v-if="showCheckBox " class="customize-table-checkbox-th"
            :class="{
              'customize-table-head-sticky': headFixed,
              'customize-table-col-sticky-left': fixedCheckbox,
              'is-checked': allCheckboxChange
            }"
            :style="{
                zIndex: (headFixed && fixedCheckbox) ? 3 : 1
            }"
            style="text-align: center;padding-left: 22px;padding-top: 10px"
        >
          <span class=" el-checkbox__input">
            <input v-show="checkModel == CheckModel.MULTIPLE" class="customize-table-checkbox"
                   :checked="allCheckboxChange" @change.stop="handleAllChange" type="checkbox"/>
            <span class="el-checkbox__inner  check-box-p-span" @click="handleAllCheckedClick"></span>
          </span>

        </th>
        <th class="customize-table-checkbox-th"
            :class="{
                'customize-table-head-sticky': headFixed,
                'customize-table-col-sticky-left': fixedLineNumber
              }"
            :style="{
                  zIndex: (headFixed && fixedCheckbox) ? 3 : 1
              }"
            v-if="showLineNumber">
          编号
        </th>
        <th style="text-align: left;padding-left: 5px;" :class="{
                'customize-table-head-sticky': headFixed,
                'customize-table-col-sticky-left': column.fixed == 'left',
                'customize-table-col-sticky-right': column.fixed == 'right'
              }"
            :style="{
                  zIndex: (headFixed && (column.fixed == 'left' || column.fixed == 'right')) ? 3 : 1
              }"
            v-for="column in columns" :key="column.field">{{ column.desc }}
        </th>
        </thead>
        <tbody>
        <tr @click.stop="handleTrClick(rowIndex)" class="customize-table-tr fade-enter-active"
            v-for="(item,rowIndex) in refData"
            :key="rowIndex" v-show="item._show || item._show == undefined">
          <td class="customize-table-checkbox-th"
              :class="{
                  'customize-table-col-sticky-left': fixedCheckbox
              }"
              v-if="showCheckBox">
            <span @click.stop class="el-checkbox__input" :class="{
                'is-checked': item.checked
            }">
              <input :checked="item.checked" class="customize-table-checkbox"
                     @change.stop="handleRowCheckboxChange(rowIndex,$event)" type="checkbox"/>
              <span class="el-checkbox__inner  check-box-p-span" @click="handleCheckedClick(rowIndex,$event)"></span>
            </span>
          </td>
          <td class="customize-table-checkbox-th"
              :class="{
                  'customize-table-col-sticky-left': fixedLineNumber
              }"
              v-if="showLineNumber">
            {{ rowIndex + 1 }}
          </td>
          <td v-for="(column, colIndex) in columns" :width="column.width == undefined ? 'auto' : column.width "
              :class="{
              'customize-table-col-sticky-left': column.fixed == 'left',
              'customize-table-col-sticky-right': column.fixed == 'right'
            }"
              :style="{
                paddingLeft: ( colIndex == 0 ? item._level * 15  : 0 ) + 'px'
              }"
          >
            <div v-if="item._hasChildren && colIndex == 0" style="float:left;padding-top: 2px;cursor: pointer">
              <el-icon @click="treeRowClick(item)">
                <component :is="Icons[item._icon]"/>
              </el-icon>
            </div>
            <div v-if="!column.isSlot">
              {{
                handleCellVal(item, column, colIndex, rowIndex)
              }}
            </div>
            <div v-if="column.isSlot">
              <slot :name="column.field" :rowData="toRaw(item)" :rowIndex="rowIndex"></slot>
            </div>
          </td>
        </tr>
        <tr v-if="refData.length <= 0">
          <td :colspan="getCols" style="text-align: center;">
            <svg width="64" height="41" viewBox="0 0 64 41" xmlns="http://www.w3.org/2000/svg">
              <g transform="translate(0 1)" fill="none" fillrule="evenodd">
                <ellipse fill="#F5F5F5" cx="32" cy="33" rx="32" ry="7"></ellipse>
                <g fillrule="nonzero" stroke="#D9D9D9">
                  <path
                      d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"></path>
                  <path
                      d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
                      fill="#FAFAFA"></path>
                </g>
              </g>
            </svg>
            <br/>
            暂无数据
          </td>
        </tr>
        </tbody>
      </table>
    </div>
    <div class="customize-table-page" v-if="showPage && !isEmpty(url)  ">
      <div class="customize-table-page-pre"
           :style="{
            'pointer-events': pageRang[0] != 1 ? 'all' : 'none'
          }"
           @click="handlePage('pre')"> &lt;
      </div>
      <div class="customize-table-page-num"
           :class="{
            'customize-table-page-num-focus' : num == activeNum
          }"
           v-for="(num,index) in pageRang " @click="handlePageNum(num)" :index="index" :key="index">{{ num }}
      </div>
      <div class="customize-table-page-next" @click="handlePage('next')"
           :style="{
            'pointer-events': pageRang[pageRang.length - 1] != pageCount ? 'all' : 'none'
          }"
      > &gt;
      </div>
      <div class="customize-table-page-input">
        当前：{{ pageCount == null ? 0 : activeNum }}&nbsp;页，共: {{ refData == undefined ? 0 : refData.length }}条
        &nbsp;
        共：{{ pageCount == null ? 0 : pageCount }}&nbsp;页，前往:&nbsp;
        <input v-model="inputPageNum" type="number" name="" @keyup.enter="goAppointPage" id="">
        &nbsp;页，每页：
        <!--        <select v-model="limit" @change="pageLimitChange" class="page-limit-select">
                  <option v-for="(item,index) in pageLimit" :value="item">{{item}}</option>
                </select>-->
        <el-select :size="'small'" v-model="limit" style="width: 60px;height: 30px" placeholder=""
                   @change="pageLimitChange">
          <el-option v-for="(item,index) in pageLimit" :label="item" :value="item"></el-option>
        </el-select>
        条
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import {computed, inject, onBeforeMount, onMounted, onUpdated, ref, toRaw, toRefs, watch} from 'vue';
import {CheckModel, TableModel, type TableOptions} from '@/components/plugs/table/TableInterface.ts';
import {AXIOS_NAME} from "@/constant/constant.ts";
import {ElMessage} from "element-plus";
import * as Icons from "@element-plus/icons-vue";
import {handleObjectDefault} from "@/utils/utils.ts";
import {ExpandedModel} from "@/components/plugs/tree/TreeView.ts";
import {isEmpty} from "lodash";

const prop = withDefaults(defineProps<TableOptions>(), {
  columns: [] as any,
  url: "",
  data: [] as any,
  handleDic: true,
  pageLimit: () => [20, 40, 80, 200],
  params: {},
  tableModel: TableModel.NORMAL,
  checkModel: CheckModel.SINGLE,
  treeConfig: TreeConfig => ({
    idField: '',
    pIdField: '',
    rootId: '',
    expand: false,
    expandModel: ExpandedModel.MULTIPLE
  }),
  showCheckBox: false,
  headFixed: true,
  showPage: true,
  showLineNumber: true,
  fixedCheckbox: true,
  fixedLineNumber: true,
  width: "100%",
  height: "100%",
  onRowCheckedChange: (selected: boolean, rowData: object, rowIndex: number) => {
  },
  onRowClick: (rowData: object, rowIndex: number) => {
  },
  onRowDblClick: (rowData: object, rowIndex: number) => {
  },
  onAllCheckedChange: (selected: boolean, data: object[]) => {
  },
  loadSuccess: (data: object[]) => {
  }
});

const {
  onRowCheckedChange, onAllCheckedChange, onRowClick,
  onRowDblClick, loadSuccess, data, params, height,
  tableModel, treeConfig, checkModel, showCheckBox, showLineNumber, columns, pageLimit
} = prop;

let {url} = prop;

watch(prop, (newValue,oldValue) => {
      url = newValue.url;
    },{
      deep: true
    });

let newTreeConfig = handleObjectDefault({expand: false}, toRaw(treeConfig));

const allCheckboxChange = ref(false);
const refData: any = ref([]);
const $axios: object = inject(AXIOS_NAME);
const pageCount = ref(0);
const showPagDiv = ref(10);//控制展示多少个页码
const limit = ref(pageLimit[0]);
const activeNum = ref(0);
const inputPageNum: any = ref(null);
const pageRang = ref([]);
const topFixed = ref(1);
const customizeTable: any = ref(null);
let searchParams: any = {};
let dicData!: any;

let html = '';

const pageLimitChange = () => {
  reload();
}

const getCols = computed(() => {
  let cols = columns.length;
  cols += showCheckBox == true ? 1 : 0;
  cols += showLineNumber == true ? 1 : 0;
  return cols;
});

const treeRowClick = (node: any) => {
  if (newTreeConfig.expandModel == ExpandedModel.SINGLE) {
    refData.value.forEach((item: any) => {
      if (node[newTreeConfig.idField] == item[newTreeConfig.idField]) {
        return;
      }
      if (newTreeConfig.rootId != item[newTreeConfig.pIdField]) {
        item._show = false;
        item._expand = false;
      } else {
        item._show = true;
        item._expand = false;
      }
      item._icon = 'CaretLeft';
    });
    node._show = true;
    node._expand = !node._expand;
    node._icon = node._expand ? 'CaretBottom' : 'CaretLeft';
    handleNodeChildrenExpandTrigger(node, node._expand);
    handleExpandedSingle(node);
    return;
  }
  node._expand = !node._expand;
  //处理子节点show问题
  handleNodeChildrenExpandTrigger(node, node._expand);
  node._icon = node._expand ? 'CaretBottom' : 'CaretLeft';
}

const handleExpandedSingle = (node: any) => {
  if (node[newTreeConfig.pIdField] == newTreeConfig.rootId) {
    return;
  }
  //关闭所有节点，打开当前节点的父节点
  refData.value.forEach((item: any) => {
    if (node[newTreeConfig.pIdField] == item[newTreeConfig.idField]) {
      item._show = true;
      item._expand = true;
      item._icon = 'CaretBottom';
      handleExpandedSingle(item);
    }
    if (item[newTreeConfig.pIdField] == node[newTreeConfig.pIdField]
        && item[newTreeConfig.idField] != node[newTreeConfig.idField]) {
      item._show = true;
      item._expand = false;
      item._icon = 'CaretLeft';
    }
  });
}

const handleNodeChildrenExpandTrigger = (node: any, state: boolean) => {
  node._icon = state ? 'CaretBottom' : 'CaretLeft';
  refData.value.forEach((item: any) => {
    if (item[newTreeConfig.pIdField] == node[newTreeConfig.idField]) {
      item._show = state;
      item._expand = false;
      if (item._hasChildren && !state) {
        handleNodeChildrenExpandTrigger(item, state);
      }
    }
  });
}

const getTreeIcon = (item: any) => {
  if (item._expand) return "CaretBottom"
  return "CaretLeft"
}

onBeforeMount(() => {
  if (isEmpty(url)) {
    refData.value = toRaw(data);
    return;
  }
  getAjaxData();
});

let timer: any;

getDicData();


const handleCellVal = (rowData: { [key: string]: string }, head: object, colIndex: number, rowIndex: number) => {
  rowData = toRaw(rowData);
  if (head.colFormatVal != undefined && head.colFormatVal != null) {
    return head.colFormatVal(rowData, dicData[head.dicType], colIndex, rowIndex);
  }
  if (head.dicType != null && head.dicType != undefined) {
    const dicItemData = dicData[head.dicType];
    if (dicItemData == null || dicItemData == undefined) {
      return rowData[head.field];
    }
    for (const item of dicItemData) {
      if (item.val == rowData[head.field]) {
        return item.text;
      }
    }
  }
  return rowData[head.field];
}

//处理行单击，双击事件
const handleTrClick = (rowIndex: number) => {
  if (timer != undefined) {
    onRowDblClick(toRaw(refData.value[rowIndex]), rowIndex);
    clearTimeout(timer);
    timer = undefined;
    return;
  }
  timer = setTimeout(function () {
    onRowClick(toRaw(refData.value[rowIndex]), rowIndex);
    clearTimeout(timer);
    timer = undefined;
  }, 400);
}

//出来table 整体checkbox事件
const handleAllChange = (event: events) => {
  const checked = event.target.checked;
  allCheckboxChange.value = checked;
  refData.value.forEach((item: any, index: number) => {
    refData.value[index].checked = checked;
  });
  onAllCheckedChange(checked, toRaw(refData.value));
}

const handleAllCheckedClick = (event: events) => {
  handleAllChange(event);
}

//处理行checkbox change事件
const handleRowCheckboxChange = (rowIndex: number, event: events) => {
  event.stopPropagation();
  event.preventDefault();
  const checked = event.target.checked;
  refData.value[rowIndex].checked = checked;
  onRowCheckedChange(checked, toRaw(refData.value[rowIndex]), rowIndex);
  if (checkModel == CheckModel.SINGLE) {
    handleCheckModelSingle(checked, rowIndex);
    return;
  }
  handleCheckModelMultiple(checked);
}
const handleCheckedClick = (rowIndex: number, event: events) => {
  debugger;
  handleRowCheckboxChange(rowIndex, event);
}
const handleCheckModelSingle = (checked: boolean, rowIndex: number) => {
  refData.value.forEach((item: any, index: number) => {
    if (index != rowIndex) {
      item.checked = false;
    }
  });
}
const handleCheckModelMultiple = (checked: boolean) => {
  if (!checked) {
    allCheckboxChange.value = false;
    return;
  }
  let flag = true;
  refData.value.forEach((item: any, index: number) => {
    if (!item.checked) {
      flag = false;
    }
  });
  allCheckboxChange.value = flag;
}

//中间页码div点击事件
const handlePageNum = (pageNum: number) => {
  activeNum.value = pageNum;
  //inputPageNum.value = pageNum;
  getAjaxData();
}

//处理翻页
const handlePage = (type: string) => {
  if (type == 'next') {
    let startNum: number = pageRang.value[pageRang.value.length - 1];
    let endNum: number = startNum + showPagDiv.value - 1;
    if (endNum > pageCount.value) {
      endNum = pageCount.value;
      startNum = pageCount.value - showPagDiv.value + 1;
    }
    handleShowPageNums(startNum, endNum);
    return;
  }
  let endNum: number = pageRang.value[0];
  let startNum: number = endNum - showPagDiv.value + 1;
  if (startNum < 1) {
    startNum = 1;
    endNum = showPagDiv.value;
  }
  handleShowPageNums(startNum, endNum);
}

function handleShowPageNums(startNum: number, endNum: number) {
  pageRang.value.splice(0, pageRang.value.length);
  if (pageCount.value <= 0) {
    return;
  }
  if (pageCount.value <= showPagDiv.value) {
    startNum = 1;
    endNum = pageCount.value;
  }
  for (let i: number = startNum; i <= endNum; i++) {
    pageRang.value.push(i);
  }
}

//跳转到指定页面
const goAppointPage = (event: events) => {
  if (inputPageNum.value < 1 || inputPageNum.value > pageCount.value) {
    inputPageNum.value = activeNum.value;
    return;
  }
  let startNum = inputPageNum.value;
  let endNum = startNum + showPagDiv.value - 1;
  if (endNum > pageCount.value) {
    endNum = pageCount.value
    startNum = pageCount.value - showPagDiv.value + 1;
  }
  handleShowPageNums(startNum, endNum);
  activeNum.value = inputPageNum.value;
  getAjaxData();
};

onMounted(() => {
  //加载完成回调
  if (isEmpty(url)) {
    calculateColsFixed();
    loadSuccess(toRaw(data));
  }
});

onUpdated(() => {
  calculateColsFixed();
  loadSuccess(toRaw(refData.value));
});


//计算table sticky
function calculateColsFixed() {
  if (refData.value.length <= 0) {
    return;
  }
  let lThs: any = customizeTable.value.querySelector("thead").querySelectorAll(".customize-table-col-sticky-left");
  let tbody: any = customizeTable.value.querySelector("tbody");
  let leftNum = 0;
  lThs.forEach((item: any, index: number) => {
    item.style.left = leftNum + "px";
    tbody.querySelectorAll("tr").forEach((tr: any) => {
      tr.querySelectorAll(".customize-table-col-sticky-left")[index].style.left = leftNum + "px";
    });
    leftNum += item.offsetWidth;
  });

  let rThs = customizeTable.value.querySelector("thead").querySelectorAll(".customize-table-col-sticky-right");
  let rightNum = 0;
  for (let i = rThs.length - 1; i >= 0; i--) {
    let item = rThs[i];
    item.style.right = rightNum + "px";
    tbody.querySelectorAll("tr").forEach((tr) => {
      tr.querySelectorAll(".customize-table-col-sticky-right")[i].style.right = rightNum + "px";
    });
    rightNum += item.offsetWidth;
  }
}

//ajax
async function getAjaxData() {
  if (isEmpty(url)) {
    return;
  }
  searchParams.start = activeNum.value;//当前页码
  searchParams.limit = limit.value;//请求数量
  for (const key in params) {
    searchParams[key] = params[key];
  }
  const result = $axios.post(url, searchParams).then(
      (response: object) => {
        const pageData = response.data;
        if (pageData.data.length <= 0 && pageData.pageCount > 0) {
          activeNum.value = 1;
          getAjaxData();
          return;
        }
        refData.value = formatData(pageData.data);
        pageCount.value = pageData.pageCount;
        allCheckboxChange.value = false;
        activeNum.value = activeNum.value == 0 ? 1 : activeNum.value;
        if (pageData.pageCount == 0 || pageData == null
            || pageData.pageCount == null || pageData.pageCount == undefined) {
          activeNum.value = 0;
          return;
        }
        let statNum = pageRang.value.length <= 0 ? 1 : pageRang.value[0];
        let endNum = pageRang.value.length <= 0 ? showPagDiv.value : pageRang.value[pageRang.value.length - 1];
        handleShowPageNums(statNum, endNum);
      }).catch((error: object) => {
    ElMessage.error("请求失败：" + error);
  }).finally(() => {
  });
}

const formatData = (data: []) => {
  if (tableModel == TableModel.NORMAL) {
    data.forEach(item => {
      item._show = true;
    })
    return data;
  }
  let result: any = [];
  formatTreeData(data, newTreeConfig.rootId, result, 1);
  return result;
}

const formatTreeData = (data: [], pId: string, result: any, level: number, pObject?: any) => {

  if (pObject != undefined) {
    pObject._hasChildren = false;
    pObject._expand = false;
  }
  for (let i = 0; i < data.length; i++) {
    let item: any = data[i];
    if (item[newTreeConfig.pIdField] == pId) {
      if (pObject != undefined) {
        pObject._hasChildren = true;
        pObject._expand = newTreeConfig.expand;
        pObject._icon = newTreeConfig.expand ? 'CaretBottom' : 'CaretLeft';
      }
      item._level = level;
      item._show = pId == newTreeConfig.rootId ? true : newTreeConfig.expand;
      result.push(item);
      let cPid: string = item[newTreeConfig.idField];
      formatTreeData(data, cPid, result, level + 1, item);
    }
  }
}

async function getDicData() {
  const result = await $axios.post("/dictionary/getGroupMapDic", {});
  const data = result.data;
  dicData = data;
}

function isJsonObject(obj: any): boolean {
  try {
    const jsonString = JSON.stringify(obj);
    const parsedObj = JSON.parse(jsonString);
    return JSON.stringify(parsedObj) === jsonString;
  } catch (error) {
    return false;
  }
}

//子组件暴露方法给父组件
const getAllData = () => {
  return toRaw(data);
}

const getCheckedData = () => {
  let temp: any[] = [];
  refData.value.forEach((item: any) => {
    if (item.checked) {
      temp.push(toRaw(item));
    }
  });
  return temp;
}

const reload = (params: any = {}, pageNum: number = 1) => {
  console.log("==========reload===============");
  console.log(url);
  activeNum.value = pageNum;
  searchParams = params == undefined || params == null ? {} : params;
  getAjaxData();
}

const getCurrentPageNum = () => {
  return activeNum.value;
}

const setData = (data: []) => {
  if (!isEmpty(url)) {
    return;
  }
  refData.value = data;
}

defineExpose({getAllData, getCheckedData, reload, getCurrentPageNum, setData});

</script>
<style scoped>

.customize-table-container {
  overflow: auto;
  position: relative;
  border: 1px solid #fbfbfb;
  font-family: Inter, Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, \5fae\8f6f\96c5\9ed1, Arial, sans-serif;
}

.customize-table {
  border: 1px solid #fbfbfb;
  border-collapse: collapse;
}

.customize-table-head-sticky {
  position: sticky;
  top: 0;
  z-index: 1;
}

.customize-table-col-sticky-left, .customize-table-col-sticky-right {
  left: 0;
  position: sticky;
  z-index: 1;
}

.customize-table td, th {
  height: 35px;
  box-sizing: border-box;
}

.customize-table th {
  color: #94979D;
  font-size: 14px;
  background-color: #fbfbfb;
}

.customize-table td {
  color: #66686B;
  padding-left: 10px;
  font-size: 14px;
}

.customize-table-checkbox-th {
  width: 50px;
  padding-left: 0px;
  text-align: center;
}


.customize-table-page {
  width: calc(100% - 10px);
  height: 35px;
  padding-top: 10px;
  display: flex;
  color: #66686B;
  padding-left: 1px;
}

.customize-table-page-num {
  width: 40px;
  height: 30px;
  font-size: 14px;
  text-align: center;
  line-height: 30px;
  cursor: pointer;
  background-color: #F0F2F5;
  margin-right: 5px;
}

.customize-table-page-num-focus {
  background-color: #409EFF;
  color: white;
}

.customize-table-page-pre, .customize-table-page-next {
  width: 30px;
  height: 30px;
  font-size: 16px;
  text-align: center;
  line-height: 30px;
  cursor: pointer;
  background-color: #F0F2F5;
  margin-right: 5px;
}

.customize-table-page-input {
  font-size: 14px;
  margin-left: 5px;
}

.customize-table-page-input input {
  width: 60px;
  height: 28px;
  border: 1px solid #F0F2F5;
  color: #75627A;
  font-size: 14px;
  border-radius: 3px;
}

.customize-table tr:nth-child(even) > td {
  background-color: #fbfbfb;
}

.customize-table tr:nth-child(odd) > td {
  background-color: white;
}

.customize-table-checkbox {
  -webkit-appearance: none; /* 移除默认样式 */
  appearance: none; /* 移除默认样式 */
  width: 14px; /* 宽度 */
  height: 14px; /* 高度 */
  border: 1px solid #DCDFE6; /* 边框样式 */
  cursor: pointer; /* 鼠标指针 */
  margin: 0px;
}

.customize-table-checkbox:checked {
  border: 1px solid #409EFF; /* 边框样式 */
  background-color: #409EFF; /* 选中时的背景颜色 */
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.check-box-p-span {
  top: 0px;
  left: -13px;
  color: white;
}

.page-limit-select {
  height: 30px;
  width: 50px;
  color: #75627A;
  font-size: 14px;
  border-radius: 3px;
  border: 1px solid #F0F2F5;
}

</style>
<style>
.el-select__wrapper {
  height: 30px;
  min-height: 30px;
}
</style>